#region Using Statements
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;
using System.Diagnostics;
#endregion

namespace Xfinity.Rendering
{
    public class SkyboxEffect : Effect
    {
        public SkyboxEffect(GraphicsDevice device, ContentManager content)
            : base(device, content.Load<Effect>("Content/Effects/Skybox"))
        {

            view = this.Parameters.GetParameterBySemantic("VIEW");
            projection = this.Parameters.GetParameterBySemantic("PROJECTION");
            texture = this.Parameters["SkyboxTexture"];
        }
        EffectParameter view, projection, texture;

        #region View
        /// <summary>
        /// View.
        /// </summary>
        public Matrix View
        {
            [DebuggerStepThroughAttribute]
            get { return view.GetValueMatrix(); }
            [DebuggerStepThroughAttribute]
            set { view.SetValue(value); }
        }
        #endregion
        #region Projection
        /// <summary>
        /// Projection.
        /// </summary>
        public Matrix Projection
        {
            [DebuggerStepThroughAttribute]
            get { return projection.GetValueMatrix(); }
            [DebuggerStepThroughAttribute]
            set { projection.SetValue(value); }
        }
        #endregion
        #region Texture
        /// <summary>
        /// Texture.
        /// </summary>
        public TextureCube Texture
        {
            [DebuggerStepThroughAttribute]
            get { return texture.GetValueTextureCube(); }
            [DebuggerStepThroughAttribute]
            set { texture.SetValue(value); }
        }
        #endregion
    }
    /// <summary>
    /// A skybox.
    /// </summary>
    public class Skybox : DrawableGameComponent
    {
        #region Private variables
        private Model skybox;
        private ContentManager content;
        #endregion
        #region Effect
        private SkyboxEffect effect;

        /// <summary>
        /// Effect.
        /// </summary>
        public SkyboxEffect Effect
        {
            get { return effect; }
        }

        #endregion
        #region Texture
        private TextureCube texture;

        /// <summary>
        /// Texture.
        /// </summary>
        public TextureCube Texture
        {
            get { return texture; }
            set { texture = value; }
        }

        #endregion
        #region TexturePath
        private string path;

        /// <summary>
        /// TexturePath.
        /// </summary>
        public string TexturePath
        {
            get { return path; }
            set
            {
                path = value;
                texture = content.Load<TextureCube>(path);
            }
        }

        #endregion
        #region Camera
        private ICamera camera;

        /// <summary>
        /// Camera.
        /// </summary>
        public ICamera Camera
        {
            get { return camera; }
            set { camera = value; }
        }

        #endregion

        public Skybox(string path, ICamera camera, Game game)
            : base(game)
        {
            this.path = path;
            this.camera = camera;
            content = new ContentManager(game.Services);
        }

        protected override void LoadGraphicsContent(bool loadAllContent)
        {
            if (loadAllContent)
            {
                texture = content.Load<TextureCube>(path);

                effect = new SkyboxEffect(GraphicsDevice, content);
                effect.Texture = texture;
                skybox = content.Load<Model>("Content/Models/Prism");
                foreach (ModelMesh mesh in skybox.Meshes)
                {
                    foreach (ModelMeshPart part in mesh.MeshParts)
                    {
                        part.Effect = effect;
                    }
                }
                
                effect.View = camera.View;
                effect.Projection = camera.Projection;
            }
            base.LoadGraphicsContent(loadAllContent);
        }
        public override void Draw(GameTime gameTime)
        {
            effect.View = camera.View;
            effect.Projection = camera.Projection;

            skybox.Meshes[0].Draw(SaveStateMode.None);

            // Undo the renderstate settings from the shader
            GraphicsDevice.RenderState.CullMode = CullMode.CullCounterClockwiseFace;
            GraphicsDevice.RenderState.DepthBufferWriteEnable = true;

            base.Draw(gameTime);
        }
    }
}